﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel.Dispatcher;
using System.ServiceModel;
using System.ServiceModel.Channels;
using WcfContrib.Extensions.OutputControllers;

namespace WcfContrib.Extensions.Context
{
    class ActivationContextInspector : IDispatchMessageInspector, IParameterInspector
    {
        internal bool CreateBufferForErrors { get; set; }
        internal bool CreateMessageBuffer { get; set; }
        
        internal Type ServiceType { get; set; }
        internal string ServiceName { get; set; }
        internal string ServiceNamespace { get; set; }

        public ActivationContextInspector(bool createMessageBuffer)
        {
            CreateMessageBuffer = createMessageBuffer;
            CreateBufferForErrors = ActivationContextInitializerBehavior.DefaultCreateBufferForErrors;
        }

        #region IDispatchMessageInspector Members

        public object AfterReceiveRequest(ref System.ServiceModel.Channels.Message request, IClientChannel channel, InstanceContext instanceContext)
        {
            OperationContext context = OperationContext.Current;

            MessageBuffer buffer = null;
            if (CreateMessageBuffer || CreateBufferForErrors)
            {
                buffer = request.CreateBufferedCopy(int.MaxValue);

                request = buffer.CreateMessage();
            }

            ActivationContextExtension extension = new ActivationContextExtension(request, buffer, CreateBufferForErrors);

            extension.ServiceType = ServiceType;
            extension.ServiceName = ServiceName;
            extension.ServiceNamespace = ServiceNamespace;

            context.Extensions.Add(extension);

            object outputState = OutputControllerManager.HandleMessage(request, false, extension, null);

            return new KeyValuePair<ActivationContextExtension, object>(extension, outputState);
        }

        public void BeforeSendReply(ref System.ServiceModel.Channels.Message reply, object correlationState)
        {
            if (correlationState != null)
            {
                KeyValuePair<ActivationContextExtension, object> state = (KeyValuePair<ActivationContextExtension, object>)correlationState;

                ActivationContextExtension extension = state.Key;

                if (extension != null)
                {
                    extension.Dispose();
                }

                OutputControllerManager.HandleMessage(reply, true, extension, state.Value);
            }
        }

        #endregion

        #region IParameterInspector Members

        public void AfterCall(string operationName, object[] outputs, object returnValue, object correlationState)
        {
        }

        public object BeforeCall(string operationName, object[] inputs)
        {
            ActivationContextExtension extension = ActivationContextExtension.Current;

            if (extension != null)
            {
                extension.SetParameters(inputs);
            }

            return null;
        }

        #endregion
    }
}
